<?php 
/**
 * ... ...
 * ... ...
 *
 */ 


/**
 * a category model ,implements by db 
 *
 * @access public
 */
class JCAT_DBAdjacensyCategory
	extends JCAT_DBModel
	implements JCAT_IAdjacensyCategory
{
	const BORDER_LEFT = 'nLft' ;
	const BORDER_RIGHT = 'nRgt' ;
	const CATEGORY_NAME = 'sName' ;
	
	/**
	 * 构造函数 
	 *
	 * @access	public 
	 * @return	void
	 */
	public function JCAT_DBAdjacensyCategory(JCAT_ORM $aORM)
	{
		if( $aORM->GetFieldByProperty(self::BORDER_LEFT)===null 
				or $aORM->GetFieldByProperty(self::BORDER_RIGHT)===null )
		{
		 	throw new JCAT_Exception(JCAT_Language::SentenceEx(
		 		'传递给 邻接分类模型(JCAT_DBAdjacensyCategory)的 ORM对象缺少必须的属性/字段映射（%s,%s）'
		 		, 'JCAT', null ,self::BORDER_LEFT, self::BORDER_RIGHT
		 	)) ;
		}
		
		$this->Loading() ;
		$this->JCAT_DBModel( $aORM ) ;
		$this->Loading(false) ;
	}

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$aModel		JCAT_DBAdjacensyCategory
	 * @return	void
	 */
	public function AddModel( JCAT_IModel $aModel, $sName=null )
	{
		JCAT_ASSERT::ASSERT_INSTANCE($aModel,'JCAT_DBAdjacensyCategory'
			, JCAT_Language::SentenceEx('参数 $aModel 必须为一个JCAT_DBAdjacensyCategory实例','JCAT',null));

		return parent::AddModel($aModel,$aModel->GetLeftBorder()) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$aAdjacensyCategory		JCAT_IAdjacensyCategory
	 * @return	void
	 */
	public function AddCategory(JCAT_IAdjacensyCategory $aInCategory)
	{
		// 设置深度
		$aInCategory->SetTreeDepth($this->GetTreeDepth()+1) ;
		
		$bDirectlyUnder = true ;
		$aIterator = $this->CreateModelIterator() ;
		for ( $aIterator->First(); !$aIterator->IsDone(); $aIterator->Next() )
		{
			$aChildCategory = $aIterator->Current() ;
			
			$nLocal = $aInCategory->Compare($aChildCategory) ;
			
			// 非所属
			if($nLocal&JCAT_IAdjacensyCategory::LOCAL_BROTHER)
			{
				continue ;
			}
			
			else if($nLocal==JCAT_IAdjacensyCategory::LOCAL_IN)
			{
				$aChildCategory->AddCategory($aInCategory) ;
				$bDirectlyUnder = false ;
				break ;
			}
			
			else if($nLocal==JCAT_IAdjacensyCategory::LOCAL_OUT)
			{
				$aInCategory->AddCategory($aChildCategory) ;
				$this->RemoveCategory($aChildCategory) ;
			}
			
			else 
			{
				throw new JCAT_Exception(JCAT_Language::SentenceEx(
					'遇到无效的邻接分类层级：(%d,%d) to (%d,%d) ?'
					, 'JCAT', null
					, $aInCategory->GetLeftBorder(), $aInCategory->GetRightBorder()
					, $aChildCategory->GetLeftBorder(), $aChildCategory->GetRightBorder()
				)) ;
			}
		}
		
		// 直属关系
		if($bDirectlyUnder)
		{
			$this->AddModel($aInCategory) ;
			$aInCategory->SetParent($this);
			
			// 子分类排序
			$this->aModelContainer->SortByName() ;
			
			// 绑定前后关系
			$this->MakeChildrenBrotherhood() ;
		}
	}
	
	/**
	 * 建立子分类的前后链表关系
	 *
	 * @access	public
	 * @return	void
	 */
	public function MakeChildrenBrotherhood()
	{
		$aIter = $this->CreateModelIterator() ;
		$aOlderBrother = null ;
		for ( $aIter->First(); !$aIter->IsDone(); $aIter->Next() )
		{
			$aItem = $aIter->Current() ;
			if($aOlderBrother)
			{
				$aOlderBrother->SetBrother($aItem,JCAT_IAdjacensyCategory::LOCAL_BEHIND) ;
				$aItem->SetBrother($aOlderBrother,JCAT_IAdjacensyCategory::LOCAL_FRONT) ;
			}
			
			$aOlderBrother = $aItem ;
		}
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	void
	 */
	public function SetBrother(JCAT_IAdjacensyCategory $aBrother=null,$nPos=JCAT_IAdjacensyCategory::LOCAL_FRONT)
	{
		$this->arrBrother[$nPos] = $aBrother ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	JCAT_IAdjacensyCategory
	 */
	public function GetBrother($nPos=JCAT_IAdjacensyCategory::LOCAL_FRONT)
	{
		return isset($this->arrBrother[$nPos])? $this->arrBrother[$nPos]: null ;
	}
	
	/**
	 * 设置对象属性 self::$aParentCategory
	 *
	 * @access	public
	 * @param	$aParentCategory=null		JCAT_IAdjacensyCategory	上级分类
	 * @return	void
	 */
	public function SetParent(JCAT_IAdjacensyCategory $aParentCategory=null)
	{
		$this->aParentCategory = $aParentCategory ;
	}
	
	/**
	 * 取得对象属性 self::$aParentCategory
	 *
	 * @access	public
	 * @return	JCAT_IAdjacensyCategory
	 */
	public function GetParent()
	{
		return $this->aParentCategory ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nTreeDepth		int
	 * @return	void
	 */
	public function SetTreeDepth($nTreeDepth)
	{
		$this->nTreeDepth = $nTreeDepth ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetTreeDepth()
	{
		return $this->nTreeDepth ;
	}
	
	/**
	 * get child categories count
	 *
	 * @access	public
	 * @param	$bRecursion=true	bool
	 * @return	int
	 */
	public function GetChildrenCount($bRecursion=true)
	{
		if($bRecursion)
		{
			$nCount = 0 ;
			// 保存下级分类
			$aIter = $this->CreateModelIterator() ;
			for ( $aIter->First(); !$aIter->IsDone(); $aIter->Next() )
			{
				$nCount ++ ;
				
				$aChildItem = $aIter->Current() ;
				$nCount+= $aChildItem->GetChildrenCount(true) ;
			}
			
			return $nCount ;
		}
		else
		{
			return $this->GetModelCount() ;
		}
	}

	/**
	 * Description
	 *
	 * @access	public
	 * @return	JCAT_IIterator
	 */
	public function CreateChildCategoryIter()
	{
		return $this->CreateModelIterator() ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$bDecoupling=true	bool	是否解除关系
	 * @return	void
	 */
	public function ClearChildren($bDecoupling=true)
	{
		if($bDecoupling)
		{
			$aIterator = $this->CreateModelIterator() ;
			for ( $aIterator->First(); !$aIterator->IsDone(); $aIterator->Next() )
			{
				$aChild = $aIterator->Current() ;
				$aChild->SetParent(null) ;
				$aChild->SetBrother(null,JCAT_IAdjacensyCategory::LOCAL_FRONT) ;
				$aChild->SetBrother(null,JCAT_IAdjacensyCategory::LOCAL_BEHIND) ;
			}
		}
		
		$this->ClearModel() ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	array
	 */
	public function GetBrothers()
	{
		$arrBrothers = array() ;
		
		$aParent = $this->GetParent() ;
		if($aParent)
		{
			$aIterator = $aParent->CreateModelIterator() ;
			for ( $aIterator->First(); !$aIterator->IsDone(); $aIterator->Next() )
			{
				$aBrother = $aIterator->Current();
				
				if($aBrother!==$this)
				{
					$arrBrothers[] = $aBrother ;
				}
			}
		}
		
		return $arrBrothers ;
	}
	
	/**
	 * 指定一个分类的id，返回这个分类的所属路径
	 *
	 * @access	public
	 * @param	$nTargetCategoryId
	 * @return	array
	 */
	public function GetCategoryPath()
	{
		$arrPath = array($this) ;
		
		$aActiveCategory = $this ;
		while( $aParent=$aActiveCategory->GetParent() )
		{
			$arrPath[] = $aParent ;
			$aActiveCategory = $aParent ;
		}
		
		return array_reverse($arrPath) ;
	}
	
	
	/**
	 * 递归地移除一个分类。 如果存在，删除并返回 true
	 *
	 * @access	public
	 * @param 	$aCategory		JCAT_IAdjacensyCategory
	 * @return	bool
	 */
	public function RemoveCategory(JCAT_IAdjacensyCategory $aCategory)
	{
		$aIterator = $this->CreateModelIterator() ;
		for ( $aIterator->First(); !$aIterator->IsDone(); $aIterator->Next() )
		{
			$aChild = $aIterator->Current();
			if( $aChild===$aCategory )
			{
				$this->RemoveModel($aCategory);
				return true ;
			}
			
			else
			{
				if( $aChild->RemoveCategory($aCategory)===true )
				{
					return true ;
				}
			}
		}
		
		return false ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$Category		JCAT_DBAdjacensyCategory,int,null
	 * @return	void
	 */
	public function AppendTo($Category=null)
	{
		JCAT_ASSERT::ASSERT_ISTHESE($Category,array('JCAT_DBAdjacensyCategory','int'));
		
		$aORM = $this->GetORM() ;
		$aDB = $aORM->GetDB() ;
	
		if( $Category instanceof JCAT_DBAdjacensyCategory )
		{
			if( !$Category->HaveSerialized() )
			{
				throw new JCAT_Exception(JCAT_Language::SentenceEx(
					'无法将一个 邻接分类Model 做为下级分类，插入到另一个尚未保存的 邻接分类Model之下。'
					, 'JCAT', null
				)) ;
			}
		
			return $this->InsertTo($Category->GetRightBorder()) ;
		}
		
		else if( is_int($Category) )
		{
			$sPrimaryKey = $aORM->GetPrimaryKey() ;
			
			$nParentRgt = $aDB->SelectOneField(
					$aORM->GetHubTable()
					, $aORM->GetFieldByProperty(self::BORDER_RIGHT)
					, "{$sPrimaryKey}={$Category}"
			) ;
					
			if( 0>=$nParentRgt )
			{
				throw new JCAT_Exception(JCAT_Language::SentenceEx(
					'无法找到指定的父级分类（primary key:%s）'
					, 'JCAT', null
					, $Category
				)) ;
			}
			
			return $this->InsertTo($nParentRgt) ;
		}
		
		else 
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'参数 $Category 必须为以下类型：JCAT_DBAdjacensyCategory,int,null'
				, 'JCAT', null
			)) ;
		}
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nPos		int
	 * @return	void
	 */
	public function InsertTo($nPos)
	{
		JCAT_ASSERT::ASSERT_($nPos>0,JCAT_Language::SentenceEx('参数 $nPos(%s) 必须大于0','JCAT',null,$nPos)) ;
		
		// 设置当前分类模型的左右边界
		$nAdjacWidth = $this->SetBorder($nPos) ;
		
		// 腾出空间
		// ------------------------
		if( !$this->Vacate($nPos,$nAdjacWidth) )
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'移动邻接分类边界失败'
				, 'JCAT', null
			)) ;
		}
		
		// 保存此model
		// ------------------------
		return $this->Create() ;
	}
	
	/**
	 * 腾出空间
	 *
	 * @access	protected
	 * @param	$nPos		int
	 * @param	$nWidth		int
	 * @return	void
	 */
	protected function Vacate($nPos,$nWidth)
	{
		$aORM = $this->GetORM() ;
		$aDB = $aORM->GetDB() ;
		$sKeyBorderRgt = $aORM->GetFieldByProperty(self::BORDER_RIGHT) ;
		$sKeyBorderLft = $aORM->GetFieldByProperty(self::BORDER_LEFT) ;
		$sHubTable = $aORM->GetHubTable() ;
		
		// 移动 右边界
		if( !$aDB->Update($sHubTable,array($sKeyBorderRgt=>JCAT_DB::e("{$sKeyBorderRgt}+{$nWidth}")),"{$sKeyBorderRgt}>={$nPos}") )
		{
			return false ;
		}
		
		// 向移动 左边界
		if( !$aDB->Update($sHubTable,array($sKeyBorderLft=>JCAT_DB::e("{$sKeyBorderLft}+{$nWidth}")),"{$sKeyBorderLft}>={$nPos}") )
		{
			return false ;
		}
		
		return true ;
	}
	
	/**
	 * Description
	 *
	 * @access	protected
	 * @param	$sLft
	 * @param	$nRgt
	 * @return	void
	 */
	protected function Contraction($sLft,$nRgt)
	{
		if( $sLft<1 or $nRgt<1 or $sLft>$nRgt )
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'无法进行邻接分类范围操作：%d,%d，', 'JCAT', null, $sLft,$nRgt
			)) ;
		}
		
		$aORM = $this->GetORM() ;
		$aDB = $aORM->GetDB() ;
		$sKeyBorderLft = $aORM->GetFieldByProperty(self::BORDER_LEFT) ;
		$sKeyBorderRgt = $aORM->GetFieldByProperty(self::BORDER_RIGHT) ;
		$sHubTable = $aORM->GetHubTable() ;
		$nWidth = $nRgt - $sLft + 1 ;
		
		// 移动后面的分类
		if( !$aDB->Update( $sHubTable
				, array($sKeyBorderLft=>JCAT_DB::e("{$sKeyBorderLft}-{$nWidth}"))
				, "{$sKeyBorderLft}>{$nRgt}" ) )
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'移动右侧邻接分类的左边界(Left Border)时遇到错误', 'JCAT', null
			)) ;
		}
		if( !$aDB->Update( $sHubTable
				, array($sKeyBorderRgt=>JCAT_DB::e("{$sKeyBorderRgt}-{$nWidth}"))
				, "{$sKeyBorderRgt}>{$nRgt}" ) )
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'移动右侧邻接分类的右边界(Right Border)时遇到错误', 'JCAT', null
			)) ;
		}
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$nPos		int
	 * @return	void
	 */
	public function MoveTo($nPos)
	{
		if($nPos<1)
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'邻接分类移动操作无效，目标位置(%s)必须大于0。'
				, 'JCAT', null, $nPos
			)) ;
		}
		
		if( !$this->HaveSerialized() or $this->GetRightBorder()<1 or $this->GetLeftBorder()<1 )
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'邻接分类Model尚未序列化，无法执行此操作。'
				, 'JCAT', null
			)) ;
		}
		
		$aORM = $this->GetORM() ;
		$aDB = $aORM->GetDB() ;
		$sKeyBorderRgt = $aORM->GetFieldByProperty(self::BORDER_RIGHT) ;
		$sKeyBorderLft = $aORM->GetFieldByProperty(self::BORDER_LEFT) ;
		$sHubTable = $aORM->GetHubTable() ;
		$nOldLft = $this->GetLeftBorder() ;
		$nOldRgt = $this->GetRightBorder() ;
		
		if( $nOldLft<=$nPos and $nPos<=$nOldRgt)
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'无法将邻接分类(%d,%d)移动至 %d, 邻接分类只能移动到自己以外的位置。'
				, 'JCAT', null, $nOldLft, $nOldRgt, $nPos
			)) ;
		}
		
		// 暂放到 1 以前
		if( !$aDB->Update($sHubTable,
			array(
				$sKeyBorderLft=>JCAT_DB::e("{$sKeyBorderLft}-{$nOldRgt}")
				, $sKeyBorderRgt=>JCAT_DB::e("{$sKeyBorderRgt}-{$nOldRgt}") )
			, "{$sKeyBorderLft} BETWEEN {$nOldLft} AND {$nOldRgt}") )
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'移动邻接分类边界失败'
				, 'JCAT', null
			)) ;
		}
		
		// 收缩移除后的空间
		$this->Contraction($nOldLft,$nOldRgt) ;
		
		$nWidth = $nOldRgt-$nOldLft + 1 ;
		
		// 如果向后移动
		if($nOldRgt<$nPos)
		{
			$nPos-= $nWidth ;
		}
		
		// 目标位置腾出空间
		if( !$this->Vacate($nPos,$nWidth) )
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'移动邻接分类边界失败'
				, 'JCAT', null
			)) ;
		}
		
		// 移动至目标
		$nMove = $nWidth + $nPos - 1 ;
		if( !$aDB->Update($sHubTable,
			array(
				$sKeyBorderLft=>JCAT_DB::e("{$sKeyBorderLft}+{$nMove}")
				, $sKeyBorderRgt=>JCAT_DB::e("{$sKeyBorderRgt}+{$nMove}") )
			, "{$sKeyBorderLft}<1") )
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'移动邻接分类边界失败'
				, 'JCAT', null
			)) ;
		}
		
		parent::Set(self::BORDER_LEFT,$nPos) ;
		parent::Set(self::BORDER_RIGHT,$nPos+$nWidth-1) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$aWith	JCAT_IAdjacensyCategory
	 * @return	void
	 */
	public function Compare(JCAT_IAdjacensyCategory $aCategory)
	{
		if( $this->GetRightBorder() < $aCategory->GetLeftBorder() )
		{
			return JCAT_IAdjacensyCategory::LOCAL_FRONT ;
		}
		
		else if( $this->GetLeftBorder() > $aCategory->GetRightBorder() )
		{
			return JCAT_IAdjacensyCategory::LOCAL_BEHIND ;
		}
		
		else if( $this->GetLeftBorder() < $aCategory->GetLeftBorder()
				and $this->GetRightBorder() > $aCategory->GetRightBorder() )
		{
			return JCAT_IAdjacensyCategory::LOCAL_OUT ;
		}
		
		else if( $this->GetLeftBorder() > $aCategory->GetLeftBorder()
				and $this->GetRightBorder() < $aCategory->GetRightBorder() )
		{
			return JCAT_IAdjacensyCategory::LOCAL_IN ;
		}
		
		else if( $this->GetLeftBorder() == $aCategory->GetLeftBorder()
				and $this->GetRightBorder() == $aCategory->GetRightBorder() )
		{
			return JCAT_IAdjacensyCategory::LOCAL_SAME ;
		}
		
		else
		{
			return JCAT_IAdjacensyCategory::LOCAL_INVALID ;
		}
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	void
	 */
	public function QueryParent()
	{
		if( !$this->HaveSerialized() or $this->GetRightBorder()<1 or $this->GetLeftBorder()<1 )
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'邻接分类Model尚未序列化，无法执行此操作。'
				, 'JCAT', null
			)) ;
		}
		
		$aORM = $this->GetORM() ;
		$aDB = $aORM->GetDB() ;
		$sKeyBorderRgt = $aORM->GetFieldByProperty(self::BORDER_RIGHT) ;
		$sKeyBorderLft = $aORM->GetFieldByProperty(self::BORDER_LEFT) ;
		$sHubTable = $aORM->GetHubTable() ;
		$nMyLft = $this->GetLeftBorder() ;
		$nMyRgt = $this->GetRightBorder() ;
		
		$aRecordset = $aDB->SelectOneRow($sHubTable
				, "{$sKeyBorderLft}<{$nMyLft} AND {$sKeyBorderRgt}>{$nMyRgt} ORDER BY {$sKeyBorderRgt}"
				, '*', JCAT_DB::RETURN_RECORDSET ) ;

		if( !$aRecordset->GetCount() )
		{
			return null ;
		}
		
		$aORM = clone $this->GetORM() ;
		$aParent = new JCAT_DBAdjacensyCategory( $aORM ) ;
		$aORMRule = $aORM->GetFieldsMappingRule() ;
		
		$bOldSetting = $aParent->Loading(true) ;
		$aORMRule->OnAfterSelect($aParent,$aRecordset) ;
		$aParent->Loading($bOldSetting) ;
		
		return $aParent ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	bool
	 */
	public function Delete()
	{
		if( !$this->HaveSerialized() )
		{
			return true ;
		}

		$nLft = $this->GetLeftBorder() ;
		$nRgt = $this->GetRightBorder() ;

		// 删除分类
		if( !parent::Delete() )
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'删除邻接分类的模式失败。', 'JCAT', null
			)) ;
			//return false ;
		}
		
		// 收缩删除后
		$this->Contraction($nRgt,$nRgt) ;
		$this->Contraction($nLft,$nLft) ;

		return true ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	void
	 */
	public function RecursionDelete()
	{
		if( !$this->HaveSerialized() )
		{
			return true ;
		}
		
		$aORM = $this->GetORM() ;
		$aDB = $aORM->GetDB() ;
		$nLft = $this->GetLeftBorder() ;
		$nRgt = $this->GetRightBorder() ;
		$sKeyBorderLft = $aORM->GetFieldByProperty(self::BORDER_LEFT) ;
		$sHubTable = $aORM->GetHubTable() ;

		// 删除分类及其
		if( !$aDB->Delete( $sHubTable, "{$sKeyBorderLft} BETWEEN {$nLft} AND {$nRgt}" ) )
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'删除邻接分类及其下级分类时遇到错误', 'JCAT', null
			)) ;
		}
		
		// 收缩删除掉的范围
		$this->Contraction($nLft,$nRgt) ;
		return true ;
	}
	
	/**
	 * if $nParentCategoryId==null, this model will be top category
	 *
	 * @access	public
	 * @return	void
	 */
	public function Create()
	{		
		// 做为顶层分类插入
		if( $this->GetLeftBorder()<1 and $this->GetRightBorder()<1 )
		{
			$aORM = $this->GetORM() ;
			$aDB = $aORM->GetDB() ;
		
			// get the max right border
			$sKeyBorderRgt = $aORM->GetFieldByProperty(self::BORDER_RIGHT) ;
			$sHubTable = $aORM->GetHubTable() ;
			
			// $aDB->Query("SELECT max({$sKeyBorderRgt}) FROM {$sHubTable}") ;
			$nMaxRgt = $aDB->SelectOneField($sHubTable,"max({$sKeyBorderRgt})") ;
			$nLft = $nMaxRgt? intval($nMaxRgt)+1: 1 ;
			
			// set left border and right border of this category
			$this->SetBorder($nLft,true) ;
		}
		
		// 递归写入下级分类
		$aIter = $this->CreateModelIterator() ;
		for ( $aIter->First(); !$aIter->IsDone(); $aIter->Next() )
		{
			$aChild = $aIter->Current() ;
			if( !$aChild->Create() )
			{
				return false ;
			}
		}
		
		// 写入操作
		return parent::Create() ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetAdjacWidth()
	{
		return 2 + $this->GetChildrenCount(true) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetLeftBorder()
	{
		return $this->Get(self::BORDER_LEFT) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetRightBorder()
	{
		return $this->Get(self::BORDER_RIGHT) ;
	}

	/**
	 * Description
	 *
	 * @access	public
	 * @return	string
	 */
	public function GetText()
	{
		return $this->Get(self::CATEGORY_NAME) ;
	}
	
	/**
	 * set this category's left and right border pos,and return the category's width
	 *
	 * @access	public
	 * @param	$nLeft		int		the left border pos
	 * @return	void
	 */
	public function SetBorder($nLeft,$bRecursion=true)
	{
		parent::Set(self::BORDER_LEFT,$nLeft) ;
		
		// 设置下级分类
		if( $bRecursion )
		{
			$nPos = $nLeft ;
			$aIter = $this->CreateModelIterator() ;
			for ( $aIter->First(); !$aIter->IsDone(); $aIter->Next() )
			{
				$aChild = $aIter->Current() ;
				
				$aChild->SetBorder(++$nPos,true) ;
				$nPos = $aChild->GetRightBorder() ;
			}
			
			// 设置自己的右边界
			parent::Set(self::BORDER_RIGHT,++$nPos) ;
			
			return $nPos-$nLeft+1 ;
		}
		
		// 不改变下级分类的左右边界
		else
		{
			$nWidth = $this->GetAdjacWidth() ;
			parent::Set(self::BORDER_RIGHT,$nLeft+$this->GetAdjacWidth()-1) ;
			return $nWidth ;
		}
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @return	void
	 */
	public function Load()
	{
		$this->Loading(true) ;
		$bRet = parent::Load() ;
		$this->Loading(false) ;
		
		return $bRet ;
	}
	
	/**
	 * Description
	 *
	 * @param	$sDataName			string	What's this Parameter ?
	 * @param	$Value				mixed	What's this Parameter ?
	 * @param	$bSetChanged=true	bool	What's this Parameter ?
	 * @return	void
	 */
	public function Set( $sDataName, $Value, $bSetChanged=true )
	{
		if( !$this->bLoading and in_array($sDataName,array(self::BORDER_LEFT,self::BORDER_RIGHT)))
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx(
				'禁止改变属性：%s'
				, 'JCAT', null
				, $sDataName
			)) ;
		}
		
		parent::Set($sDataName, $Value, $bSetChanged) ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param	$bLoading=true
	 * @return	void
	 */
	public function Loading($bLoading=true)
	{
		$this->bLoading = $bLoading ;
	}
	
	
	// 属性 ///////////////////////////////////
	
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		int
	 */
	private $nTreeDepth = -1 ;
	
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		bool
	 */
	private $bLoading = false ;
	
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		array
	 */
	private $arrBrother = array(
		JCAT_IAdjacensyCategory::LOCAL_BEHIND => null 
		, JCAT_IAdjacensyCategory::LOCAL_FRONT => null
	) ;
	
	
	/**
	 * 对象属性 上级分类
	 * 
	 * @access	private
	 * @var		JCAT_DBAdjacensyCategory
	 */
	private $aParentCategory ;
}


?>